package org.jeecg.common.model;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.*;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.BeanConvertUtil;
import org.jeecg.common.util.FieldUtil;
import org.jeecg.common.util.GenericUtil;
import org.jeecg.common.util.ImportExcelUtil;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StreamUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 导入模板基础类
 * @author mzz
 */
@Slf4j
public abstract class BaseImportModel<T> {

    /**
     * 获取导入模板文件
     * @return
     */
    protected abstract String getTemplateFilePath();

    /**
     * 模块名 前端调用导入接口，下载模板接口的时候需要用到
     * @return
     */
    public String moduleName(){
        String moduleName = GenericUtil.getGeneric(this.getClass(), (generics) -> {
            Class<T> cls = (Class) generics[0];
            String simpleName = cls.getSimpleName();
            simpleName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
            return simpleName;
        });
        return moduleName;
    }

    /**
     * 导入数据
     */
    public Result importData(HttpServletRequest request) {
        String modelFilePath = getTemplateFilePath();
        AtomicReference<Result> result = new AtomicReference<>(Result.OK());
        List<String> errorMessageList = new ArrayList<>();

        if(request instanceof MultipartHttpServletRequest){
            ((MultipartHttpServletRequest)request).getFileNames().forEachRemaining(fileName->{
                MultipartFile file =  ((MultipartHttpServletRequest)request).getFile(fileName);
                if (file != null) {
                    List<T> dataList = null;
                    try {
                        dataList = getDataList(modelFilePath, file.getInputStream());
                        if (CollectionUtils.isEmpty(dataList)) {
                            throw new JeecgBootException("导入文件中无有效数据，请检查");
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                    //按长度排序
                    preImport(dataList);//导入前
                    int num = 0;
                    for (T t : dataList) {
                        try{
                            validateRowDate(t);
                            saveData(t);
                        }catch (Exception e){
                            log.error(e.getMessage(),e);
                            String message ;
                            if(e instanceof JeecgBootException){
                                message = e.getMessage();
                            }else{
                                message = "服务异常";
                            }
                            errorMessageList.add("第"+(num+1)+"行："+ message);
                        }
                        num++;

                    }
                    afterImport(dataList);//导入后操作
                    Result<?> r = ImportExcelUtil.imporReturnRes(errorMessageList.size(), dataList.size() - errorMessageList.size(), errorMessageList);
                    result.set(r);

                }
            });

        }
        return result.get();
    }

    /**
     * 排序，赋值等
     * @param dataList
     */
    protected void preImport(List<T> dataList ){

    }
    /**
     * 校验字段
     */
    protected ImportValidetor validateEmptyField(){
        return null;
    }
    /**
     * 校验每一条数据
     */
    private void validateRowDate(T rowData){
        ImportValidetor importValidetor = validateEmptyField();
        if(importValidetor!=null){
            for (Map.Entry<String,String> entry : importValidetor.entrySet()) {
                String fieldName = entry.getKey();
                Object value = FieldUtil.getFieldValueByName(rowData, fieldName);
                if(value==null||value.toString().trim().equals("")){
                    throw new JeecgBootException(entry.getValue()+"不能为空！");
                }
            }
        }
    }

    /**
     * @param dataList
     */
    protected void afterImport(List<T> dataList ){

    }


    /**
     * 提取【导入】的数据列表
     *
     * @param modelFilePath
     *            数据导入时对应的数据模板文件
     * @param stream
     *            用户上传时的流文件
     * @return
     * @throws IOException
     */
    private List getDataList(String modelFilePath, InputStream stream)
            throws IOException {
        List<Map<String, Object>> dataList = new ArrayList<>();
        InputStream fi = null;
        Workbook hwb = null;
        Row row = null;
        Cell cell = null;
        HashMap<String, String> cellField = new HashMap<String, String>();
        int dataRowStart = 0;
        // 获取绑定及对应列位置
        try {
            ClassPathResource classPathResource = new ClassPathResource(modelFilePath);

            fi = classPathResource.getInputStream();
            hwb = WorkbookFactory.create(fi);
            Sheet sheet = hwb.getSheetAt(0);
            int rows = sheet.getLastRowNum();
            int cols = -1;
            for (int i = 0; i <= rows; i++) {
                row = sheet.getRow(i);
                if (row == null) {
                    continue;
                }
                cols = row.getLastCellNum();
                for (int j = 0; j < cols; j++) {
                    cell = row.getCell(j);
                    String value = "";
                    if (null != cell) {
                        value = cell.getRichStringCellValue().toString();
                        if (value.indexOf("${") != -1) {
                            // 数据位置
                            dataRowStart = i;
                            cellField.put("" + j,
                                    value.substring(value.indexOf("{") + 1, value.indexOf("}")));
                        }

                    }
                }
            }
            // 根据绑定的字段获取数据列表
            if (cellField.keySet() != null) {
                hwb = WorkbookFactory.create(stream);
                sheet = hwb.getSheetAt(0);
                rows = sheet.getLastRowNum();
                cols = -1;
                for (int i = dataRowStart; i <= rows; i++) {
                    row = sheet.getRow(i);
                    if (row == null) {
                        continue;
                    }
                    cols = row.getLastCellNum();
                    Map<String, Object> rowData = new HashMap();
                    // 当前行是否所有列都为空
                    boolean isNotNull = false;
                    for (int j = 0; j < cols; j++) {
                        cell = row.getCell(j);
                        String cellValue = "";
                        if (null != cell) {
                            switch (cell.getCellType()) {
                                case HSSFCell.CELL_TYPE_NUMERIC:
                                    if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                        double d = cell.getNumericCellValue();
                                        Date date = HSSFDateUtil.getJavaDate(d);
                                        SimpleDateFormat dformat = new SimpleDateFormat("yyyy-MM-dd");
                                        cellValue = dformat.format(date);
                                    } else {
                                        NumberFormat nf = NumberFormat.getInstance();
                                        nf.setGroupingUsed(false); // true时的格式：1,234,567,890
                                        cellValue = nf.format(cell.getNumericCellValue()); // 数值类型的数据为double，所以需要转换一下
                                    }
                                    break;
                                case HSSFCell.CELL_TYPE_STRING:
                                    cellValue = cell.getStringCellValue();
                                    break;
                                case HSSFCell.CELL_TYPE_BOOLEAN:
                                    cellValue = String.valueOf(cell.getBooleanCellValue());
                                    break;
                                case HSSFCell.CELL_TYPE_FORMULA:
                                    cellValue = String.valueOf(cell.getCellFormula());
                                    break;

                                default:
                                    cellValue = "";
                                    break;
                            }
                            // 获取对应绑定字段（包含表名标识）
                            String fullField = cellField.get("" + j) == null ? "" : cellField.get(
                                    "" + j).toString();
                            if (!"".equals(fullField)) {
                                rowData.put(fullField, cellValue.trim());
                            }
                            if (!"".equals(cellValue)) {
                                isNotNull = true;
                            }
                        }
                    }
                    if (isNotNull) {
                        dataList.add(rowData);
                    }
                    isNotNull = false;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fi != null) {
                fi.close();
            }
        }
        Class<T> c = GenericUtil.getGeneric(this.getClass(), (generics) -> {
            if(generics!=null){
                Class<T> cla = (Class) generics[0];
                return cla;
            }
            return null;
        });
        if(c!=null){
            List<T> data = BeanConvertUtil.convert(dataList, c);
            return data;
        }

        return dataList;
    }
    /**
     * 保存导入的数据
     */
    protected abstract void saveData( T data);


    /**
     * 下载导入模板
     * @return
     * @throws Exception
     */
    public ResponseEntity<byte[]> downloadImportTemplate() throws Exception {
        String templateFilePath = getTemplateFilePath();
        String type = templateFilePath.substring(templateFilePath.lastIndexOf(".") + 1);
        String downloadTemplateFilePath = templateFilePath.substring(0,templateFilePath.lastIndexOf("."))+"_demo."+type;//下载模板默认按模板文件_template.xls
        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment",  URLEncoder.encode(getDemoFileName()+"."+type,"utf-8"));//下载后显示的名字
        ClassPathResource classPathResource = new ClassPathResource(downloadTemplateFilePath);
        InputStream inputStream = classPathResource.getInputStream();
        byte[] bytes = StreamUtils.copyToByteArray(inputStream);
        return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
    }

    /**
     * 导入模板名称
     * @return
     */
    protected String getDemoFileName(){
        return "导入模板";
    }


    /**
     * 获取模板文件名，使用多种浏览器防止乱码
     * @param fileName
     * @return
     * @throws Exception
     */
    private String getDownloadFileName(String fileName,HttpServletRequest request) throws Exception {

        String userAgent = getBrowserName(request.getHeader("USER-AGENT").toLowerCase());
        String downloadFile = null;
        if (userAgent.contains("firefox")) {//火狐浏览器
            downloadFile = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
        } else {
            downloadFile = URLEncoder.encode(fileName, "UTF8");//其他浏览器
        }
        return downloadFile;
    }


    private  String getBrowserName(String agent) {
        if(agent.indexOf("msie 7")>0){
            return "ie7";
        }else if(agent.indexOf("msie 8")>0){
            return "ie8";
        }else if(agent.indexOf("msie 9")>0){
            return "ie9";
        }else if(agent.indexOf("msie 10")>0){
            return "ie10";
        }else if(agent.indexOf("msie")>0){
            return "ie";
        }else if(agent.indexOf("opera")>0){
            return "opera";
        }else if(agent.indexOf("firefox")>0){
            return "firefox";
        }else if(agent.indexOf("webkit")>0){
            return "webkit";
        }else if(agent.indexOf("gecko")>0 && agent.indexOf("rv:11")>0){
            return "ie11";
        }else{
            return "Others";
        }
    }

    public static class ImportValidetor extends HashMap<String,String>{

        public static ImportValidetor instanec(){
            return new ImportValidetor();
        }
        public ImportValidetor addValidate(String fieldName,String desc){
            this.put(fieldName,desc);
            return this;
        }

    }

}
